#include "vc1dec_definitions.h"
#include "vc1stream.h"
#include "vc1dec_api.h"
#include "vc1vlc.h"

I16_VC1 VC1GetDCStepSize(I16_VC1 pquant)
{
	I16_VC1 stepsize = 0;
	if(pquant <= 2)
		stepsize = pquant << 1;
	else if(pquant <= 4)
		stepsize = 8;
	else
		stepsize = (pquant >> 1) + 6;
	return stepsize;
}

I16_VC1 VC1DeZigzagAC(sVC1Decoder* pDec,I16_VC1* coef,I16_VC1* tmpCoef,I8_VC1 direction)
{
	return 0;
}

I16_VC1 VC1CopyDCACPredictor(sVC1MB* pCur,I16_VC1* coef)
{
	I32_VC1 i;
	///top
	memcpy(pCur->acTop,&coef[1],sizeof(I16_VC1)*7);
	////left
	for(i = 0; i < 7; i++)
		pCur->acLeft[i] = coef[i+8];

	return 0;

}

I16_VC1 ApplyACPrediction(I16_VC1* coef,I16_VC1* preAC,I32_VC1 stride)
{
	I16_VC1 i;
	I16_VC1* dst = &coef[stride];
	I16_VC1* src = preAC;
	for(i = 0; i < 7; i++)
	{
		*dst = *dst + *src;
		dst+=stride;
		src++;
	}
}

I16_VC1 VC1DecodeACRunLevel(sVC1Decoder* pDec,sVC1Stream* pStream,I16_VC1* coef)
{
	I32_VC1 position = 0;
	I32_VC1 run,level,last_flag;
	U16_VC1 index;
	sVC1RL* pACRLTable = pDec->pACRLTable;
	U16_VC1 *pACDeltaRun_0 = pDec->pACDeltaRunTable_0;
	U16_VC1 *pACDeltaRun_1 = pDec->pACDeltaRunTable_1;
	U16_VC1 *pACDeltaLevel_0 = pDec->pACDeltaLevelTable_0;
	U16_VC1 *pACDeltaLevel_1 = pDec->pACDeltaLevelTable_1;

	do
	{
		index = VC1GetVLC(pStream,pDec->pACIRLTable,VC1ACPEEKBITS);
		if(index == ESCAPE)
		{
			I8_VC1 sign = 0;
			run = pACRLTable[index].run;
			level = pACRLTable[index].level;
			last_flag = pACRLTable[index].last;
			sign = VC1GetBits(pStream,1);
			if(sign == 1)
				level = -level;
		}
		else
		{
			I8_VC1 escmode = VC1ShowBits(pStream,2);
			
			if(escmode >= 2)
			{
				escmode = 2;
				VC1DumpBits(pStream,1);
			}
			else
				VC1DumpBits(pStream,2);

			if(escmode == 2)///mode 1
			{
				U16_VC1 index = 0;
				I8_VC1 sign = 0;
				index = VC1GetVLC(pStream,pDec->pACIRLTable,VC1ACPEEKBITS);
				run = pACRLTable[index].run;
				level = pACRLTable[index].level;
				last_flag = pACRLTable[index].last;

				if(last_flag == 0)
					level += pACDeltaLevel_0[run];
				else
					level += pACDeltaLevel_1[run];

				sign = VC1GetBits(pStream,1);
				if(sign)
					level = -level;
					
			}
			else if(escmode == 1)///mode 2
			{
				U16_VC1 index = 0;
				I8_VC1 sign = 0;
				index = VC1GetVLC(pStream,pDec->pACIRLTable,VC1ACPEEKBITS);
				run = pACRLTable[index].run;
				level = pACRLTable[index].level;
				last_flag = pACRLTable[index].last;

				if(last_flag == 0)
					run += pACDeltaRun_0[level];
				else
					run += pACDeltaRun_1[level];

				sign = VC1GetBits(pStream,1);
				if(sign)
					level = -level;
			}
			else  ///mode 3
			{
				I8_VC1 sign = 0;
				last_flag = VC1GetBits(pStream,1);
				if(pDec->first_mode3 == 1)
				{
					pDec->first_mode3 = 0;
					if(pDec->pquant <= 7 || pDec->boundryedge == 0)
					{
						I8_VC1 tmp = VC1GetBits(pStream,3);
						if(tmp > 0)
							pDec->level_size = tmp;
						else
						{
							tmp = VC1GetBits(pStream,2);
							pDec->level_size = 8 + tmp;
						}
					}
					else
					{
						I32_VC1 counter = 0;
						while(counter < 6)
						{
							if(VC1GetBits(pStream,1))
								break;

							counter++;
						}
						
						pDec->level_size = counter + 2;
						
					}

					pDec->run_size = 2 + VC1GetBits(pStream,2);
				}

				run = VC1GetBits(pStream,pDec->run_size);
				sign = VC1GetBits(pStream,1);
				level = VC1GetBits(pStream,pDec->level_size);
				if(sign)
					level = -level;
			}
		}

		coef[position + run] = level;
		position += run + 1;
	}while(1 != last_flag);

	return 0;
}

HRESULT_VC1 VC1DecIntraBlock(sVC1Decoder* pDec,sVC1MB* pCur,I32_VC1* neighbor,I16_VC1* coef,I32_VC1 blk)
{
	HRESULT_VC1 rt = VC1_OK;
	I32_VC1 i;
	sVC1Stream* pStream = &pDec->stream;
	I16_VC1 DCDiff = 0;
	U32_VC1 quant = pCur->mquant;
	I32_VC1 isAdv = (pDec->profile < VC1_eProfileAdvanced) ? 0 : 1;
	I16_VC1 LeftDC,TopDC,LTDC,PredictorDC;
	I8_VC1  PredDirection = 0;/////left 0  top 1;
	I16_VC1* acPredCoef = NULL;
	I16_VC1 tmpCoef[64] = {0};

	I16_VC1 default_dc = pCur->default_dc;

	//////decode DC differential
	if(blk <= 3)////luma block
		DCDiff = VC1GetVLC(pStream,pDec->pLumaDCTable,VC1DCDIFFVLCPEEKBITS);
	else
		DCDiff = VC1GetVLC(pStream,pDec->pChroDCTable,VC1DCDIFFVLCPEEKBITS);
	if(DCDiff != 0)
	{
		I8_VC1 DCSign = 0;
		if(DCDiff == VC1DCDIFFESCAPE)
		{
			if(quant == 1)
				DCDiff = VC1GetBits(pStream,10);
			else if(quant == 2)
				DCDiff = VC1GetBits(pStream,9);
			else
				DCDiff = VC1GetBits(pStream,8);
		}
		else
		{
			if(quant == 1)
				DCDiff = (DCDiff << 2) + VC1GetBits(pStream,2) - 3;
			else if(quant == 2)
				DCDiff = (DCDiff << 1) + VC1GetBits(pStream,1) - 1;
		}

		DCSign = VC1GetBits(pStream,1);
		if(DCSign == 1)
			DCDiff = -DCDiff;
	}

	//////
	switch(blk)
	{
	case 0:
		if(neighbor[0])
		{
			sVC1MB* left = pCur - 1;
			if(left->isIntra[1])
				LeftDC = left->DC[1];
			else
				LeftDC = default_dc;
		}
		else
			LeftDC = default_dc;

		if(neighbor[1])
		{
			sVC1MB* top = pCur - pDec->widthMBs;
			if(top->isIntra[2])
				TopDC = top->DC[2];
			else
				TopDC = default_dc;
		}
		else
			TopDC = default_dc;

		if(neighbor[2])
		{
			sVC1MB* lt = pCur - pDec->widthMBs - 1;
			if(lt->isIntra[3])
				LTDC = lt->DC[3];
			else
				LTDC = default_dc;
		}
		else
			LTDC = default_dc;
		break;
	case 1:
		LeftDC = pCur->isIntra[0] ? pCur->DC[0] : default_dc;
		if(neighbor[1])
		{
			sVC1MB* top = pCur - pDec->widthMBs;
			if(top->isIntra[2])
				LTDC = top->DC[2];
			else
				LTDC = default_dc;

			if(top->isIntra[3])
				TopDC = top->DC[3];
			else
				TopDC = default_dc;
		}
		else
		{
			TopDC = default_dc;
			LTDC = default_dc;
		}
		break;
	case 2:
		TopDC = pCur->isIntra[0] ? pCur->DC[0] : default_dc;
		if(neighbor[2])
		{
			sVC1MB* left = pCur - 1;
			if(left->isIntra[3])
				LeftDC = left->DC[3];
			else
				LeftDC = default_dc;

			if(left->isIntra[1])
				LTDC = left->DC[1];
			else
				LTDC = default_dc;
		}
		else
		{
			LeftDC = default_dc;
			LTDC = default_dc;
		}
		break;
	case 3:
		LeftDC = pCur->isIntra[2] ? pCur->DC[2] : default_dc;
		TopDC  = pCur->isIntra[1] ? pCur->DC[1] : default_dc;
		LTDC   = pCur->isIntra[0] ? pCur->DC[0] : default_dc;
		break;
	case 4:
	case 5:
		if(neighbor[0])
		{
			sVC1MB* left = pCur - 1;
			if(left->isIntra[blk])
				LeftDC = left->DC[blk];
			else
				LeftDC = default_dc;
		}
		else
			LeftDC = default_dc;

		if(neighbor[1])
		{
			sVC1MB* top = pCur - pDec->widthMBs;
			if(top->isIntra[blk])
				TopDC = top->DC[blk];
			else
				TopDC = default_dc;
		}
		else
			TopDC = default_dc;

		if(neighbor[2])
		{
			sVC1MB* lt = pCur - pDec->widthMBs - 1;
			if(lt->isIntra[blk])
				LTDC = lt->DC[blk];
			else
				LTDC = default_dc;
		}
		else
			LTDC = default_dc;
		break;
	}

	/////////decide prediction direction
	if(pDec->profile < VC1_eProfileAdvanced)///simple/main profile
	{
		if(ABS(LTDC-LeftDC) >= ABS(LTDC-TopDC))
		{
			PredDirection = 1;
			PredictorDC = TopDC;
		}
		else
		{
			PredDirection = 0;
			PredictorDC = LeftDC;
		}
	}
	else
		return VC1_INVALIDPROFILE;/////unsupported


	coef[0] = tmpCoef[0] = PredictorDC + DCDiff;
	///////decode ac run level
	if((pCur->CBP >> (5 - blk)) & 1)
	{
		VC1DecodeACRunLevel(pDec,pStream,&tmpCoef[1]);
		////de-zigzag here
		VC1DeZigzagAC(pDec,coef,tmpCoef,PredDirection);
	}

	if(pCur->acpred && pDec->profile < VC1_eProfileAdvanced)///simple/main profile
	{
		I32_VC1 stride = 0;
		if(PredDirection == 0)///left
		{
			stride = 8;
			acPredCoef = pCur->acLeft + sizeof(I16_VC1)*7*blk;
		}
		else//top
		{
			stride = 1;
			acPredCoef = pCur->acTop + sizeof(I16_VC1)*7*blk;
		}

		ApplyACPrediction(coef,acPredCoef,stride);
	}
	else
		return VC1_INVALIDPROFILE;/////unsupported


	/////copy the dc ac to prediction array
	VC1CopyDCACPredictor(pCur,coef);

	return rt;
}
HRESULT_VC1 VC1DecInterBlock(sVC1Decoder* pDec,sVC1MB* pCur,I32_VC1* neighbor,I16_VC1* coef,I32_VC1 blk)
{
	HRESULT_VC1 rt = VC1_OK;
	return rt;
}

HRESULT_VC1 VC1DecBlocks(sVC1Decoder* pDec,sVC1MB* pCur,I32_VC1* neighbor,U8_VC1* pY,U8_VC1* pU,U8_VC1* pV,I32_VC1 x)
{
	HRESULT_VC1 rt = VC1_OK;
	I32_VC1 i = 0;
	I16_VC1 coef[NUM_BLOCKS][64];

    for(i = 0; i < 6; i++)
	{
		if(pCur->isIntra[i])////intra block
			rt = VC1DecIntraBlock(pDec,pCur,neighbor,&coef[i][0],i);
		else
			rt = VC1DecInterBlock(pDec,pCur,neighbor,&coef[i][0],i);

		if(rt != VC1_OK)
			return rt;
	}
	return rt;
}

